<?php
/**
 * 微信支付
 * author:www.tong-kuai.com
 */

namespace Api\Controller;

use Think\Controller;

class PayController extends Controller
{

    protected $user_id;

    protected $wxPayAppid;
    protected $wxPayAppsecret;
    protected $wxPayMchid;
    protected $wxPayKey;
//    支付回调地址
    protected $callback_url;

    function __construct()
    {
        parent::__construct();
        $this->wxPayAppid = C('THINK_SDK_WEIXIN_PAY.APP_ID_PAY');
        $this->wxPayAppsecret = C('THINK_SDK_WEIXIN_PAY.APP_SECRET_PAY');
        $this->wxPayMchid = C('THINK_SDK_WEIXIN_PAY.MCH_ID_PAY');
        $this->wxPayKey = C('THINK_SDK_WEIXIN_PAY.APP_KEY_PAY');
        $this->callback_url= sp_get_host() . __ROOT__ . '/index.php?g=api&m=oauth&a=callback&type=';
    }

    /**
     * 微信小程序调起支付
     */
    public function getWXPayData()
    {
        $this->user_id = I("userid");

        $postid = $_GET['postid'];

        $rscode = $this->getWXPayInfo($postid);
        if ($rscode['rscode']) {
            exit(json_encode(array('status' => -1, 'result' => $rscode,'42'=>'')));
        } else {
            $return_arr = array('status' => 1, 'msg' => '成功', 'result' => $rscode); // 返回结果状态
            exit(json_encode($return_arr));
        }
    }

    /**
     * 生成微信小程序支付信息
     * @param $postid 文章id
     * @return mixed
     */
    public function getWXPayInfo($postid)
    {
        $reward_model = M('Reward');
        $posts_model = M('Posts');

        $data = array(
            'sn_no' => date('YmdHis') . rand(1000, 9999), // 订单编号
            'posts_id' => $postid,
            'oauth_user' => $this->user_id,
            'accounts' => 0.01,//$this->randomFloat(1, 5),
            'creat_time' => time()
        );

        $posts = $posts_model->where(array('id' => $postid))->find();

        $rewardid = $reward_model->data($data)->add();
        if (!$rewardid) {
            $rs['rscode'] = 'FAIL';
            $rs['rs']='保存赏金失败！';
            return $rs;
        }
        $orderBody = $posts['post_title'];
        $tade_no = $data['sn_no'];
        $total_fee = $data['accounts'];

        $response = $this->getPrePayOrder($orderBody, $tade_no, $total_fee);

        if ($response['return_code'] == "FAIL") {
            $rs['rscode'] = 'FAIL';
            $rs['rs'] = $response;
            $rs['87'] = $data['accounts'];
            return $rs;
        }

        $x = $this->getOrder($response['prepay_id']);

        $data1['wdata'] = $x;
        $data1['pay_money'] = $data['accounts'];

        return $data1;
    }

    public function getPrePayOrder($body, $out_trade_no, $total_fee)
    {
        $user = M('OauthUser')->where("id = {$this->user_id}")->find();
        $openId = $user['openid'];

        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $notify_url = $this->callback_url.'wxpay';

        $onoce_str = $this->getRandChar(32);
        $data["appid"] = $this->wxPayAppid;
        $data["mch_id"] = $this->wxPayMchid;
        $data["nonce_str"] = $onoce_str;
        $data["body"] = $body;
        $data["out_trade_no"] = $out_trade_no;
        $data["total_fee"] = $total_fee*100;
//        $data["spbill_create_ip"] = $this->get_client_ip();
        $data["spbill_create_ip"] = '114.215.25.12';
        $data["notify_url"] = $notify_url;
        $data["trade_type"] = "JSAPI";
        $data["openid"] = $openId;
        $s = $this->MakeSign($data, false);
        $data["sign"] = $s;
        $xml = $this->arrayToXml($data);
        $response = $this->postXmlCurl($xml, $url);

        // 将微信返回的结果xml转成数组
        return $this->xmlstr_to_array($response);
    }

    // 执行第二次签名，才能返回给客户端使用
    public function getOrder($prepayId)
    {
        $data["appId"] = $this->wxPayAppid;
        $data["nonceStr"] = $this->getRandChar(32);
        $data["package"] = "prepay_id=" . $prepayId;
        $data['signType'] = "MD5";
        $data["timeStamp"] = time();

        $s = $this->getSign1($data, false);
        $data["sign"] = $s;
        return $data;
    }

    /**
     * 生成随机2位小数
     * @param int $min
     * @param int $max
     * @return string
     */
    function randomFloat($min = 0, $max = 10)
    {
        $num = $min + mt_rand() / mt_getrandmax() * ($max - $min);
        return sprintf("%.2f", $num);

    }

    // 获取指定长度的随机字符串
    function getRandChar($length)
    {
        $str = null;
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol) - 1;

        for ($i = 0; $i < $length; $i++) {
            $str .= $strPol[rand(0, $max)]; // rand($min,$max)生成介于min和max两个数之间的一个随机整数
        }

        return $str;
    }

    /**
     * 将参数拼接为url: key=value&key=value
     * @param   $params
     * @return  string
     */
    public function ToUrlParams($params)
    {
        $string = '';
        if (!empty($params)) {
            $array = array();
            foreach ($params as $key => $value) {
                $array[] = $key . '=' . $value;
            }
            $string = implode("&", $array);
        }
        return $string;
    }

    /**
     * 生成签名
     * @return 签名
     */
    public function MakeSign($params)
    {
        //签名步骤一：按字典序排序数组参数
        ksort($params);
        $string = $this->ToUrlParams($params);
//        return $string;
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=" . $this->wxPayKey;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    /*
     * 生成签名
     */
    function getSign($Obj)
    {
        foreach ($Obj as $k => $v) {
            $Parameters[strtolower($k)] = $v;
        }
        // 签名步骤一：按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        // echo "【string】 =".$String."</br>";
        // 签名步骤二：在string后加入KEY
        $String = $String . "&key=" . $this->wxPayKey;
        // echo "<textarea style='width: 50%; height: 150px;'>$String</textarea> <br />";
        // 签名步骤三：MD5加密
        $result_ = strtoupper(md5($String));
        return $result_;
    }

    /*
     * 生成签名
     */
    function getSign1($Obj)
    {
        foreach ($Obj as $k => $v) {
            $Parameters[strtolower($k)] = $v;
        }
        // 签名步骤一：按字典序排序参数
        ksort($Parameters);
        //$String = $this->formatBizQueryParaMap($Parameters, false);
        $String = "appId=" . $Obj['appId'] . "&nonceStr=" . $Obj['nonceStr'] . "&package=" . $Obj['package'] . "&signType=MD5&timeStamp=" . $Obj['timeStamp'];

        // echo "【string】 =".$String."</br>";
        // 签名步骤二：在string后加入KEY
        $String = $String . "&key=" . $this->wxPayKey;
        // echo "<textarea style='width: 50%; height: 150px;'>$String</textarea> <br />";
        // 签名步骤三：MD5加密
        //echo $String;
        $result_ = strtoupper(md5($String));
        return $result_;
    }

    /*
     * 获取当前服务器的IP
     */
    function get_client_ip()
    {
        if ($_SERVER['REMOTE_ADDR']) {
            $cip = $_SERVER['REMOTE_ADDR'];
        } elseif (getenv("REMOTE_ADDR")) {
            $cip = getenv("REMOTE_ADDR");
        } elseif (getenv("HTTP_CLIENT_IP")) {
            $cip = getenv("HTTP_CLIENT_IP");
        } else {
            $cip = "unknown";
        }
        return $cip;
    }

    // 数组转xml
    function arrayToXml($arr)
    {

        $xml = "<xml>";

        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
        }
        $xml .= "</xml>";


        return $xml;
    }

    // post https请求，CURLOPT_POSTFIELDS xml格式
    function postXmlCurl($xml, $url, $second = 30)
    {
        // 初始化curl
        $ch = curl_init();
        // 超时时间
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        // 这里设置代理，如果有的话
        // curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        // curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        // 设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        // 要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        // post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        // 运行curl
        $data = curl_exec($ch);

        // 返回结果
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            echo "curl出错，错误码:$error" . "<br>";
            echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
            curl_close($ch);
            return "curl出错，错误码:$error" . "<br>";
        }
    }

    /**
     * xml转成数组
     */
    function xmlstr_to_array($xmlstr)
    {
        //$doc = new \DOMDocument();
        //$doc->loadXML($xmlstr);
        //return $this->domnode_to_array($doc->documentElement);

        //禁止引用外部xml实体

        libxml_disable_entity_loader(true);

        $xmlstring = simplexml_load_string($xmlstr, 'SimpleXMLElement', LIBXML_NOCDATA);

        $val = json_decode(json_encode($xmlstring),true);

        return $val;


    }
}

